package com.authsphere.security.captcha;

import com.authsphere.common.entity.PluginData;
import com.authsphere.common.enums.PluginBeforeEnum;
import com.authsphere.plugin.api.AuthSphereBeforePluginChain;
import com.authsphere.plugin.api.WebExchange;
import com.authsphere.plugin.base.AbstractAuthSphereBeforePlugin;
import com.authsphere.plugin.base.cache.AnnotationDataCache;
import com.authsphere.plugin.base.entity.AnnotationFieldBean;
import com.authsphere.plugin.base.utils.AnnotationProcessor;
import com.authsphere.common.annotation.CaptchaField;
import com.authsphere.security.captcha.config.CaptchaConfig;
import com.authsphere.common.enums.ParamType;
import com.authsphere.security.captcha.exception.CaptchaAuthenticationException;
import com.authsphere.security.captcha.service.GraphicalCaptchaService;
import jakarta.servlet.http.Cookie;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @program: AuthSphere
 * @description:
 * @author: YuKai Fan
 * @create: 2025/3/25 17:01
 **/
public class CaptchaBeforePlugin extends AbstractAuthSphereBeforePlugin {

    private final CaptchaConfig captchaConfig;
    private final GraphicalCaptchaService graphicalCaptchaService;

    public CaptchaBeforePlugin(CaptchaConfig captchaConfig, GraphicalCaptchaService graphicalCaptchaService) {
        this.captchaConfig = captchaConfig;
        this.graphicalCaptchaService = graphicalCaptchaService;
    }

    @Override
    protected void doExecute(WebExchange exchange, AuthSphereBeforePluginChain chain, PluginData pluginData) {
        String captchaKey = extractCaptcha(exchange);
        if (StringUtils.isBlank(captchaKey)) {
            throw new CaptchaAuthenticationException("请校验图形验证码");
        }
        boolean verification = graphicalCaptchaService.verification(captchaKey);
        if (!verification) {
            throw new CaptchaAuthenticationException("图形验证码错误，请重新校验");
        }
        chain.execute(exchange);
    }

    private String extractCaptcha(WebExchange exchange) {
        ParamType paramType = captchaConfig.getParamType();
        return switch (paramType) {
            case BODY -> getAnnotatedValue(exchange);
            case PARAM -> exchange.getRequest().getParameter(captchaConfig.getParamName());
            case HEADER -> exchange.getRequest().getHeader(captchaConfig.getParamName());
            case COOKIE -> getValueFromCookie(exchange);
            default -> "";
        };
    }

    private String getValueFromCookie(WebExchange exchange) {
        Cookie[] cookies = exchange.getRequest().getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals(captchaConfig.getParamName())) {
                    return cookie.getValue();
                }
            }
        }
        return null;
    }

    private static String getAnnotatedValue(WebExchange exchange) {
        Object requestBody = exchange.getRequestBody();
        if (requestBody == null) {
            return null;
        }
        AnnotationFieldBean<CaptchaField> annotationData = AnnotationDataCache.getAnnotationData(requestBody.getClass(), CaptchaField.class);
        if (annotationData == null) {
            return null;
        }
        try {
            return (String) annotationData.getGetterMethod().invoke(requestBody);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new CaptchaAuthenticationException("获取图形验证码失败", e);
        }
    }

    @Override
    public int getOrder() {
        return PluginBeforeEnum.CAPTCHA.getCode();
    }

    @Override
    public String name() {
        return PluginBeforeEnum.CAPTCHA.getName();
    }
}
